var debug_obj_str = function(obj) {
  var str = "";
  for (var i in  obj) {
    str += (i + ": " + obj[i] + ",  ")
  }
  return str; 
}


var load_resources = function(done_cb) {
  var image_src = ['black.png', 'white.jpg'];
  var images = {};

  var pending = image_src.length;
  var image_cb = function() {
    pending--;
    if (pending == 0) done_cb(images);
  };

  var load_img = function(src) {
    var img = new Image();
    img.onload = image_cb;
    img.src = src;
    return img;
  };

  for (var i = 0; i < image_src.length; ++i) {
    var src = image_src[i];
    images[src] = load_img(src);
  }
  return images;
};


var new_renderer_ =
    function(container_elem, resources, board_size) {
  
  var display_w = container_elem.offsetWidth;
  var cell_width = Math.floor(display_w / board_size); 
  var cvs_w = cell_width * board_size;

  var setup_display_ctx_ = function() {
    var cvs = document.createElement('canvas');
    cvs.width = display_w;
    cvs.height = display_w;
    container_elem.appendChild(cvs);
    var cvs_ctx = cvs.getContext('2d');
    if (!cvs_ctx) throw new Error('Cannot get ctx');
    return cvs_ctx;
  };

  var setup_grid_ = function() {
    var cvs = document.createElement('canvas');
    cvs.width = display_w;
    cvs.height = display_w;
    var cvs_ctx = cvs.getContext('2d');
    if (!cvs_ctx) throw new Error("cannot get ctx");

    cvs_ctx.beginPath();
    var offset = cell_width / 2;
    for (var i = 0; i < board_size; i++) {
      var y = offset + i * cell_width;
      cvs_ctx.moveTo(offset, y);
      cvs_ctx.lineTo(offset + cell_width * (board_size - 1), y);
    }

    for (var i = 0; i < board_size; i++) {
      var x = offset + i * cell_width;
      cvs_ctx.moveTo(x, offset);
      cvs_ctx.lineTo(x, offset + cell_width * (board_size - 1));
    }
    cvs_ctx.stroke();
    cvs_ctx.closePath();
    return cvs;
  };

  var setup_stones_layer_ = function() {
    var cvs = document.createElement('canvas');
    cvs.width = display_w;
    cvs.height = display_w;
    var cvs_ctx = cvs.getContext('2d');
    if (!cvs_ctx) throw new Error("cannot get ctx");
    return {
      elem: cvs,
      ctx: cvs_ctx
    };
  };

  var setup_stone = function(img) {
    var cvs = document.createElement('canvas');
    cvs.width = cell_width;
    cvs.height = cell_width;
    var cvs_ctx = cvs.getContext('2d');
    if (!cvs_ctx) throw new Error("cannot get ctx");
    cvs_ctx.drawImage(img, 5, 5, cell_width - 10, cell_width - 10);
    console.log(cell_width);
    return cvs;
  };

  var print_ = function(x, y, c) {
    alert("x" + x + "y" + y + "c" + c);
  };

  var white_stone = setup_stone(resources['white.jpg']);
  var black_stone = setup_stone(resources['black.png']);
  var ctx = setup_display_ctx_();
  var grid_ctx = setup_grid_();
  var stones_layer = setup_stones_layer_();

  var coord_to_pos_ = function(cx, cy) {
    var offset = cell_width / 2;
    bx = Math.floor(cx / cell_width);
    by = Math.floor(cy / cell_width);
    if (bx >= 0 && bx < board_size &&
        by >= 0 && by < board_size) {
      return [bx, by];
    } else {
      return [];
    }
  };

  var add_stone_ = function(x, y, colour) {
    ctx.clearRect(0, 0, cvs_w, cvs_w);
    ctx.drawImage(grid_ctx, 0, 0);

    var c = (colour == 0) ? white_stone : black_stone;
    stones_layer.ctx.drawImage(c, x * cell_width, y * cell_width);
    ctx.drawImage(stones_layer.elem, 0, 0)
  };

  var hover_stone_ = function(x, y, colour) {
    ctx.clearRect(0, 0, cvs_w, cvs_w);
    ctx.drawImage(grid_ctx, 0, 0);
    ctx.drawImage(stones_layer.elem, 0, 0)

    var c = (colour == 0) ? white_stone : black_stone;
    ctx.drawImage(c, x * cell_width, y * cell_width);
  }

  var clear_ = function() {
    ctx.clearRect(0, 0, cvs_w, cvs_w);
    stones_layer.ctx.clearRect(0, 0, cvs_w, cvs_w);
    ctx.drawImage(grid_ctx, 0, 0);
  };


  var redraw = function() {
    ctx.clearRect(0, 0, cvs_w, cvs_w);

  }

  var board_event_handler = { hover: function() {}, placeStone: function() {}  };

  var mouse_handler_ = function(event) {
    var element = event.target;
    var elementX = event.clientX - element.offsetLeft;
    var elementY = event.clientY - element.offsetTop;
    // console.log(elementX + " " + elementY + " " + event.clientX + " " + event.clientY); 
    var new_pos = coord_to_pos_(elementX, elementY);

    if (event.type == 'mousemove') {
      board_event_handler.hover(new_pos);
    } else if (event.type == 'click') {
      board_event_handler.placeStone(new_pos); 
    } else {
      console.log(event.type);
    }
    
  };

  container_elem.addEventListener('mousemove', mouse_handler_, true);
  container_elem.addEventListener('click', mouse_handler_, true);


  return {
    clear: clear_,
    drawStone: add_stone_,
    hoverStone: hover_stone_,
    onremove: function(x, y) {},
    setBoardHandler: function(b) {
      board_event_handler = b;
    }
  };
};


var new_board = function(size, renderer) {
  var size_ = size;
  var pieces_ = {};


  var mutate_ = function(mutation) {
    for (var i in mutation.add) {
      pieces_[i] = mutation.add[i];
    }

    for (var i in mutation.remove) {
      delete pieces_[i];
    }
  };

  var xy_to_pos_ = function(x, y) {
    if (x >= size_ || y >= size_) {
      throw new Error("xy out of bounds: " + x + " " + y);
    };
    return x + y * size_;
  }

  var pos_to_xy_ = function(pos) {
    if (pos >= size_ * size_) {
      throw new Error("pos out of bounds: " + pos);
    }
    return { x: pos % size_, y: pos / size_ };
  };


  var add_stone_to_mutation_ = function(mutation, xpos, ypos, colour) {
    var pos = xy_to_pos_(xpos, ypos);
    mutation.add[pos] = colour;
  }; 

  var new_mutation_ = function() {
    return {add: {}, remove: {}};
  }

  renderer.clear();

  var board_event_handler = {
    hover: function(pos) {
      renderer.hoverStone(pos[0], pos[1], 1);
    },
    placeStone: function(pos) {
      renderer.drawStone(pos[0], pos[1], 1); 
    }
  };

  renderer.setBoardHandler(board_event_handler);

  return {
    get_size : function() { return size_; },
    mutate: mutate_,
    add_stone: function(xpos, ypos, colour) { 
      var m = new_mutation_();
      add_stone_to_mutation_(m, xpos, ypos, colour);
      mutate_(m); 
      renderer.drawStone(xpos, ypos, colour);
    },
    debug_print: function() {
      alert(debug_obj_str(pieces_));
    }
  };
};


